package com.ysu.zyw.common.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.ysu.zyw.common.tool.Tuple;

/**
 * UploadUtil provide an set of operation for upload.
 * <p>
 * Created by ZeRur on 2016/1/17.
 *
 * @author yaowu.zhang
 */
public class UploadUtil {

    /**
     * 阿里云上传类
     */
    @SuppressWarnings("JavaDoc")
    public static class AliOssUploader {

        public static final String DEFAULT_BUCKET_NAME = "zr-resources";

        private static final String ENDPOINT = "http://oss-cn-beijing.aliyuncs.com";

        private static final String ACCESS_KEY_ID = EncryptUtil
                .aesDecrypt("wYjGz7ixY2N3EoN2KEw5VwZD3s/M4eTCCs8QiJFk4PY=", System.getProperty("user.name"));

        private static final String ACCESS_KEY_SECRET = EncryptUtil
                .aesDecrypt("P4ik+65rkex/W0qzxKiQITwk7ZZLCmA75LQDHp4wjdM=", System.getProperty("user.name"));

        public static final String DOWNLOAD_URL_PREFIX = "http://zr-resources.oss-cn-beijing.aliyuncs.com/";

        private static OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET,
                new ClientConfiguration());

        /**
         * 从路径上传文件
         *
         * @param bucketName     Bucket名字
         * @param objectKey      文件对象的key 可以为如下形式 folder_name/file_name.prefix folder_name为阿里云的文件夹抽象(其实是一个大小为0的对象)
         *                       file_name为文件的名字 一般用UUID prefix为文件的后缀名
         * @param pathname       文件的路径
         * @param objectMetadata 文件的元信息 主要用来设置 ContentType 也可以通过 addUserMetadata 设置用户自定义信息
         * @return Tuple<String, PutObjectResult> FirstValue String 文件地址 SecondValue PutObjectResult 上传结果
         */
        public static Tuple<String, PutObjectResult> upload(String bucketName, String objectKey, String pathname,
                                                            ObjectMetadata objectMetadata) throws FileNotFoundException {
            return upload(bucketName, objectKey, new File(pathname), objectMetadata);
        }

        /**
         * 从MultipartFile上传文件
         *
         * @param bucketName     Bucket名字
         * @param objectKey      文件对象的key 可以为如下形式 folder_name/file_name.prefix folder_name为阿里云的文件夹抽象(其实是一个大小为0的对象)
         *                       file_name为文件的名字 一般用UUID prefix为文件的后缀名
         * @param multipartFile  SpringMVC上传抽象
         * @param objectMetadata 文件的元信息 主要用来设置 ContentType 也可以通过 addUserMetadata 设置用户自定义信息
         * @return Tuple<String, PutObjectResult> FirstValue String 文件地址 SecondValue PutObjectResult 上传结果
         */
        public static Tuple<String, PutObjectResult> upload(String bucketName, String objectKey,
                                                            MultipartFile multipartFile, ObjectMetadata objectMetadata) throws IOException {
            return upload(bucketName, objectKey, multipartFile.getInputStream(), multipartFile.getSize(),
                    objectMetadata);
        }

        /**
         * 从File上传文件
         *
         * @param bucketName     Bucket名字
         * @param objectKey      文件对象的key 可以为如下形式 folder_name/file_name.prefix folder_name为阿里云的文件夹抽象(其实是一个大小为0的对象)
         *                       file_name为文件的名字 一般用UUID prefix为文件的后缀名
         * @param file           文件
         * @param objectMetadata 文件的元信息 主要用来设置 ContentType 也可以通过 addUserMetadata 设置用户自定义信息
         * @return Tuple<String, PutObjectResult> FirstValue String 文件地址 SecondValue PutObjectResult 上传结果
         */
        public static Tuple<String, PutObjectResult> upload(String bucketName, String objectKey, File file,
                                                            ObjectMetadata objectMetadata) throws FileNotFoundException {
            return upload(bucketName, objectKey, new FileInputStream(file), file.length(), objectMetadata);
        }

        /**
         * 从InputStream上传文件
         *
         * @param bucketName     Bucket名字
         * @param objectKey      文件对象的key 可以为如下形式 folder_name/file_name.prefix folder_name为阿里云的文件夹抽象(其实是一个大小为0的对象)
         *                       file_name为文件的名字 一般用UUID prefix为文件的后缀名
         * @param inputStream    文件流
         * @param fileSize       文件的大小
         * @param objectMetadata 文件的元信息 主要用来设置 ContentType 也可以通过 addUserMetadata 设置用户自定义信息
         * @return Tuple<String, PutObjectResult> FirstValue String 文件地址 SecondValue PutObjectResult 上传结果
         */
        public static Tuple<String, PutObjectResult> upload(String bucketName, String objectKey,
                                                            InputStream inputStream, Long fileSize, ObjectMetadata objectMetadata) {
            objectMetadata.setContentLength(fileSize);
            return new Tuple<>(DOWNLOAD_URL_PREFIX + objectKey,
                    ossClient.putObject(bucketName, objectKey, inputStream, objectMetadata));
        }

        /**
         * 载入文件
         *
         * @param bucketName Bucket名字
         * @param objectKey  文件对象的Key 包含folder_name和prefix
         * @return Tuple<InputStream, ObjectMetadata> FirstValue InputStream 文件的流 SecondValue ObjectMetadata
         * 文件的元信息
         */
        public static Tuple<InputStream, ObjectMetadata> load(String bucketName, String objectKey) {
            OSSObject object = ossClient.getObject(bucketName, objectKey);
            return new Tuple<>(object.getObjectContent(), object.getObjectMetadata());
        }

        /**
         * 下载文件到指定位置
         *
         * @param bucketName Bucket名字
         * @param objectKey  文件对象的Key 包含folder_name和prefix
         * @return ObjectMetadata 文件的元信息
         */
        public static ObjectMetadata download(String bucketName, String objectKey, String filePath) {
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectKey);
            return ossClient.getObject(getObjectRequest, new File(filePath));
        }

        /**
         * 删除文件
         *
         * @param bucketName Bucket名字
         * @param objectKey  文件对象的Key 包含folder_name和prefix
         */
        public static void delete(String bucketName, String objectKey) {
            ossClient.deleteObject(bucketName, objectKey);
        }

        /**
         * 创建文件夹
         *
         * @param bucketName Bucket名字
         * @param folderKey  文件夹对象Key 例如 folder1/folder2
         */
        public static PutObjectResult createFolder(String bucketName, String folderKey) throws IOException {
            byte[] byteBuffer = new byte[0];
            try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteBuffer)) {
                ObjectMetadata objectMeta = new ObjectMetadata();
                objectMeta.setContentLength(0);
                return ossClient.putObject(bucketName, folderKey + "/", byteArrayInputStream, objectMeta);
            }
        }

        /**
         * 删除文件夹
         *
         * @param bucketName Bucket名字
         * @param folderKey  文件夹对象Key 例如 folder1/folder2
         */
        public static void deleteFolder(String bucketName, String folderKey) {
            ossClient.deleteObject(bucketName, folderKey + "/");
        }

    }

}
